package zhongbo.java.air.monitor.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;
import zhongbo.java.air.common.vo.PageVo;
import zhongbo.java.air.monitor.dto.PointDto;
import zhongbo.java.air.monitor.mapper.JtsMapper;
import zhongbo.java.air.monitor.model.AirAlertLog;
import zhongbo.java.air.monitor.service.IJtsService;
import zhongbo.java.air.monitor.util.JtsUtil;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class JtsServiceImpl implements IJtsService {

    @Autowired
    private JtsMapper jtsMapper;

    /*
   多边形至少4个点数据, 第一个数据和最后一个数据一致, 表示点位闭合
   比如三角形最少3个点, 再加一个结束闭合点, 一共需要4个点;
        首点    一点  二点   末尾点(与首点重合)
   如: [[0,0],[0,1],[1,1],[0,0]]
   多边形示例:
   [
       {"longitude":115.95,"latitude":40.45},
       {"longitude":115.95,"latitude":39.48},
       {"longitude":117.2,"latitude":39.41},
       {"longitude":117.49,"latitude":40.41},
       {"longitude":115.95,"latitude":40.45}
   ]
    */

    @Override
    public List<PointDto> parseAlertZoneVertices(String vertices) {
        // Coordinate coordinate = new Coordinate()
        JSONArray jsonArray = JSONUtil.parseArray(vertices);
        List<PointDto> pointList = jsonArray.toList(PointDto.class);
        if (!validAreaPointList(pointList)) {
            return null;
        }
        return pointList;
    }

    /**
     * 校验多边型是否合法
     * @param pointList 多边形构成点 列表
     * @return
     */
    private boolean validAreaPointList(List<PointDto> pointList) {
        if (pointList == null) {
            log.error("校验失败! 多边形点位数据为 null");
            return false;
        }
        if (pointList.size() < 4) { // 0 1 2 3 最开始和最后的点必须是同一处,必须组成三角形及以上
            log.error("校验失败! 多边形点位数据数量错误: {}", pointList);
            return false;
        }
        PointDto firstPoint = pointList.get(0);
        PointDto lastPoint = pointList.get(pointList.size() - 1); // 取最后一个下标
        if (!firstPoint.equals(lastPoint)) {
            log.error("校验失败! 多边形点位数据数量错误: {}",pointList);
            return false;
        }
        return true;
    }

    @Override
    public boolean isInAlertZone(List<PointDto> pointList, Double longitude, Double latitude) {
        if (!validAreaPointList(pointList)) {
            throw new RuntimeException("无效的区域多边形");
        }
        Polygon polygon = convertToPolygon(pointList);

        Point point = JtsUtil.createPoint(longitude, latitude);

        return JtsUtil.isPointInPolygon(point, polygon); // 点 是否在 区域 内
    }

    /**
     * 转换为多边形对象
     *
     * @param pointList 多边形数据列表
     * @return Polygon
     */    private Polygon convertToPolygon(List<PointDto> pointList) {
        List<Coordinate> coordinateList = pointList.stream().map(l -> {
                    Double longitude = l.getLongitude();
                    Double latitude = l.getLatitude();
                    return JtsUtil.createCoordinate(longitude,latitude);
                }).collect(Collectors.toList());
        Coordinate[] coordinates = ArrayUtil.toArray(coordinateList, Coordinate.class);

        return JtsUtil.createPolygon(coordinates);
    }


    /* 以下是复用crud */




    @Override
    public String addAirAlertLog(AirAlertLog airAlertLog) {
        if (airAlertLog == null) {
            throw new RuntimeException("警告信息记录对象为空");
        }

        int insert = jtsMapper.insert(airAlertLog);
        if (insert > 0) {
            return airAlertLog.getId();
        }
        throw new RuntimeException("新增警告信息记录失败");
    }

    @Override
    public AirAlertLog updateAirAlertLog(AirAlertLog airAlertLog) {
        if (airAlertLog == null) {
            throw new RuntimeException("警告信息对象为空");
        }

        int update = jtsMapper.updateById(airAlertLog);
        if (update > 0) {
            return airAlertLog;
        }
        throw new RuntimeException("修改警告信息记录失败");
    }

    @Override
    public int deleteAirAlertLog(String airId) {
        if (airId == null) {
            throw new RuntimeException("未找到警告信息对象id");
        }

        int delete = jtsMapper.deleteById(airId);
        if (delete > 0) {
            return delete;
        }
        throw new RuntimeException("删除警告信息记录失败");
    }

    @Override
    public AirAlertLog getAirAlertLogById(String airId) {
        if (airId == null) {
            throw new RuntimeException("未找到警告信息对象id");
        }
        return jtsMapper.selectById(airId);
    }

//    @Override
//    public List<AirAlertLog> getAirAlertLogAll() {
//        return AirAlertLogMapper.getAirFlightPathAll();
//    }

    @Override
    public PageVo<AirAlertLog> page(String icaoCode, int pageNumber, int pageSize) {
        QueryWrapper<AirAlertLog> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(icaoCode)) {
            queryWrapper.like("icao_code",icaoCode);
        }
        IPage pageParam = new Page(pageNumber,pageSize);
        IPage airFlightPage = jtsMapper.selectPage(pageParam,queryWrapper);
        return new PageVo<>(airFlightPage);
    }

//    @Override
//    public PageVo<AirAlertLog> pageTimeFlightPathAll(String icao, Date startTime, Date endTime, Integer pageNumber, Integer pageSize) {
//        QueryWrapper<AirAlertLog> queryWrapper = new QueryWrapper();
//        if (StrUtil.isNotBlank(icao)) {
//            queryWrapper.like("icao_code",icao).between("timestamp",startTime,endTime);
//        }
//        IPage pageParam = new Page(pageNumber,pageSize);
//        IPage airIngestion = AirAlertLogMapper.selectPage(pageParam,queryWrapper);
//        return new PageVo<>(airIngestion);
//    }

}
